package main

import (
	"fmt"
	"github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/disk"
	"github.com/shirou/gopsutil/mem"
	"os/exec"
	"strings"
	"time"
)

type MacInfo struct {
	OSType      string `json:"os_type"`
	OSVersion   string `json:"os_version"`
	SN          string `json:"sn"`
	CPUType     string `json:"cpu_type"`
	CPUSize     string `json:"cpu_size"`
	CPUUsage    string `json:"cpu_usage"`
	MemoryType  string `json:"memory_type"`
	MemorySize  string `json:"memory_size"`
	MemoryUsage string `json:"memory_usage"`
	DiskSize    string `json:"disk_size"`
	DiskUsage   string `json:"disk_usage"`
}
type ChData struct {
	data1 string
	data2 string
}

func main() {
	start := time.Now()
	macinfo := MacInfo{}
	ch1 := make(chan string)
	go getMacSn(ch1)
	macinfo.SN = <-ch1
	ch2 := make(chan ChData)
	go getCPUInfo(ch2)
	if data, ok := <-ch2; ok {
		macinfo.CPUType = data.data1
		macinfo.CPUSize = data.data2
	}
	ch3 := make(chan string)
	go getMemorySize(ch3)
	macinfo.MemorySize = <-ch3
	ch4 := make(chan string)
	go getMemoryType(ch4)
	macinfo.MemoryType = <-ch4
	ch5 := make(chan ChData)
	go getDiskInfo(ch5)
	if data, ok := <-ch5; ok {
		macinfo.DiskSize = data.data1
		macinfo.DiskUsage = data.data2
	}
	ch6 := make(chan ChData)
	go getOSInfo(ch6)
	if data, ok := <-ch6; ok {
		macinfo.OSType = data.data1
		macinfo.OSVersion = data.data2
	}
	ch7 := make(chan ChData)
	go getCpuAndMemoryUsage(ch7)
	if data, ok := <-ch7; ok {
		macinfo.CPUUsage = data.data1
		macinfo.MemoryUsage = data.data2
	}
	fmt.Println(macinfo)
	elapsed := time.Since(start)
	fmt.Println("本次运行耗时：", elapsed)
}
func getMacSn(ch chan string) {
	out, err := exec.Command("system_profiler", "SPHardwareDataType").Output()
	if err != nil {
		ch <- ""
		return
	}
	output := string(out)
	start := strings.Index(output, "Serial Number (system):") + 24
	end := start + 12
	ch <- output[start:end]
}
func getCPUInfo(ch chan ChData) {
	out, err := exec.Command("sysctl", "machdep.cpu.brand_string", "machdep.cpu.core_count").Output()
	if err != nil {
		ch <- ChData{
			data1: "",
			data2: "",
		}
		return
	}
	output := string(out)
	cpuTypeStart := strings.Index(output, "machdep.cpu.brand_string: ") + 26
	cpuTypeEnd := strings.Index(output[cpuTypeStart:], "\n") + cpuTypeStart
	cpuType := output[cpuTypeStart:cpuTypeEnd]
	coreCountStart := strings.Index(output, "machdep.cpu.core_count: ") + 24
	coreCountEnd := strings.Index(output[coreCountStart:], "\n") + coreCountStart
	coreCount := output[coreCountStart:coreCountEnd]
	ch <- ChData{
		data1: cpuType,
		data2: coreCount,
	}
}

func getMemorySize(ch chan string) {
	cmd := exec.Command("system_profiler", "SPHardwareDataType")
	output, err := cmd.Output()
	if err != nil {
		ch <- ""
		return
	}
	start := strings.Index(string(output), "Memory:") + 7
	size := string(output[start : start+12])
	size = strings.ReplaceAll(size, " ", "")
	ch <- strings.TrimSpace(size)

}
func getMemoryType(ch chan string) {
	output, err := exec.Command("system_profiler", "SPMemoryDataType").Output()
	if err != nil {
		ch <- ""
		return
	}
	data := string(output)
	start := strings.Index(data, "Type:") + 5
	memory_type := data[start : start+12]
	memory_type = strings.ReplaceAll(memory_type, " ", "")
	ch <- strings.TrimSpace(memory_type)
}
func getDiskInfo(ch chan ChData) {
	cmd := exec.Command("diskutil", "info", "/")
	output, err := cmd.Output()
	if err != nil {
		ch <- ChData{}
		return
	}
	data := string(output)
	start := strings.Index(data, "Disk Size:") + 10
	end := strings.Index(data, "Device Block Size:")
	d := data[start:end]
	index := strings.Index(d, "(")
	d = d[:index]
	diskSize := strings.ReplaceAll(d, " ", "")
	diskUsage, err := disk.Usage("/")
	if err != nil {
		ch <- ChData{
			data1: diskSize,
			data2: "",
		}
	}
	ch <- ChData{
		data1: diskSize,
		data2: fmt.Sprintf("%.2f%%\n", diskUsage.UsedPercent),
	}
}
func getOSInfo(ch chan ChData) {
	out, err := exec.Command("sw_vers").Output()
	if err != nil {
		ch <- ChData{
			data1: "",
			data2: "",
		}
		return
	}
	output := string(out)
	OSType := strings.Split(strings.Split(output, "\n")[0], ":")[1]
	version := strings.Split(strings.Split(output, "\n")[1], ":")[1]
	ch <- ChData{
		data1: strings.TrimSpace(OSType),
		data2: strings.TrimSpace(version),
	}
}
func getCpuAndMemoryUsage(ch chan ChData) {
	percent, err := cpu.Percent(0, true)
	if err != nil {
		ch <- ChData{}
	}
	var total float64
	for _, p := range percent {
		total += p
	}
	cpu_usage := fmt.Sprintf("%.2f%%\n", total)

	virtualMem, err := mem.VirtualMemory()
	if err != nil {
		ch <- ChData{
			data1: cpu_usage,
		}
	}
	memory_usage := fmt.Sprintf("%.2f%%\n", virtualMem.UsedPercent)
	ch <- ChData{
		data1: cpu_usage,
		data2: memory_usage,
	}
}
